/**
 * This is the testcase file to simulate the positive and negative test cases
 * for assignment # 2 - system call implementations
 */

#include "syscall.h"

/**
 * This method is to simulation invalid destory condition
 */

void createConditionInUse()
{
	int lockId,conditionId;
	conditionId = CreateCondition((char *)"conditionInUse",14);
	lockId = CreateLock((char *)"lockInUse",9);
	Acquire(lockId);
	Wait(conditionId,lockId);
	Release(lockId);
	Exit(0);

}
/**
 * This method is to simulation invalid destory condition
 */
void deleteInUseCondition()
{
	int cvId=1;
	DestroyCondition(cvId);
	Exit(0);
}



/**
 * This function is created to prove the correctness of the fork system call.
 */
void forktest()
{
	Print("Inside the forked function\n");
	Exit(0);
}

/**
 * This function is created to prove the correctness of the destroy system call.
 */
void threadtest()
{
	Print("Inside the thread function\n");
	Exit(0);
}

/**
 * The testcases to prove the correctness of the "CreateLock" implementation
 */
void testcase1()
{
	int lockId=-1;
	int i=0;

	Print("CREATELOCK SYSTEM CALL TEST\n\n");
	Print("*********************************************************\n");
	Print("NEGATIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test1] Invalid lockname : \nInserted lock name which is exceeding the maximum length\n");
	lockId = CreateLock((char *)"testlongnameforthelockexceedingthelimitofcharacter",40);

	Print("--------------------------------------------------------\n");
	Print("[Test2] Invalid locklength : \nnegative lock length passed to simulate error\n");
	lockId = CreateLock((char *)"negativelength",-2);

	Print("--------------------------------------------------------\n");
	Print("[Test3] Address limit exceeding  :\nSimulating error by trying to create Lock in invalid address-space\n");
	lockId = CreateLock((char *)0xffffff00,10);


	Print("--------------------------------------------------------\n");
	Print("[Test4] Exceed maximum lock limit : \n5 additional locks created to simulate error\n");

	for(i=0;i<505;i++)
	{
		CreateLock((char *)"lock",10);
	}

	Print("\n\n\n\nDestroying some locks so that test can proceed further normally...\n\n\n");
	for(i=1;i<5;i++)
	{
	lockId = i;
	DestroyLock(lockId);
	}

	Print("\n\n*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");

	Print("[Test1] Creating 3 Locks successfully : \n3 locks created to simulate success scenario\n");

	for(i=0;i<3;i++)
	{
		Print1("Lock created with ID = %d\n",(CreateLock((char *)"lock",10)));
	}

	Exit(0);

}

/**
 * The testcases to prove the correctness of the "DestroyLock" implementation
 */
void testcase2()
{
	int lockId=-1;
	int rv;

	Print("DESTROYLOCK SYSTEM CALL TEST\n\n");
	Print("*********************************************************\n");
	Print("NEGATIVE TEST CASES\n");
	Print("*********************************************************\n");

	Print("[Test1] Invalid lock id : \nInserted lock name which is exceeding the maximum number of allowed locks\n");
	DestroyLock(1000);

	Print("--------------------------------------------------------\n");
	Print("[Test2] Invalid Lock Delete : \nTrying to delete a lock which is already deleted to simulate error\n");
	lockId = CreateLock((char *)"dummyLock",9);
	DestroyLock(lockId);
	DestroyLock(lockId);

	Print("--------------------------------------------------------\n");
	Print("[Test3] Invalid Lock Delete : \nTrying to delete a lock which was never created\n");
	DestroyLock(450);

	Print("--------------------------------------------------------\n");
	Print("[Test4] Invalid Lock Delete : \nTrying to delete a lock which does not belong to current Process\n");

	rv = Exec("../test/exec",12);
	DestroyLock(0);

	Print("--------------------------------------------------------\n");
	Print("[Test5] Invalid Lock Delete : \nTrying to delete a lock which is currently in use\n");

	lockId = CreateLock((char *)"lockInUse",9);
	Acquire(lockId);
	DestroyLock(lockId);
	Release(lockId);

	Print("\n\n*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test1] Delete a Lock \nCreated one lock , then deleted it\n");
	lockId = CreateLock((char *)"lockdelete",10);
	DestroyLock(lockId);
	Exit(0);
}

/**
 * The testcases to prove the correctness of the "CreateCondition" implementation
 */
void testcase3()
{
	int i,conditionId=-1;

	Print("CREATECONDITION SYSTEM CALL TEST\n\n");
	Print("*********************************************************\n");
	Print("NEGATIVE TEST CASES\n");
	Print("*********************************************************\n");

	Print("[Test1] Illegal CV name\nCondition variable name length is illegal\n");
	conditionId = CreateCondition((char *)"condition",50);
	Print("--------------------------------------------------------\n");

	Print("[Test2] Illegal CV name\nCondition variable name length passed is -ve\n");
	conditionId = CreateCondition((char *)"condition",-1);
	Print("--------------------------------------------------------\n");

	Print("[Test3] Address limit exceeding  :\nSimulating error by trying to creating a condition variable in invalid address-space\n");
	conditionId = CreateCondition((char *)0xffffff00,10);
	Print("--------------------------------------------------------\n");

	Print("[Test4] CV exceeding limit\n5 Additional CV's created over maximum limit\n");
	for(i=0;i<2005;i++)
	{
		conditionId = CreateCondition((char *)"condition",9);
	}

	Print("\n\n\n\nDestroying some conditions vars so that test can proceed further normally...\n\n\n");
	for(i=1;i<4;i++)
	{
		conditionId = i;
		DestroyCondition(conditionId);
	}

	Print("\n\n*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test1] Creating a condition variable\n");
	conditionId = CreateCondition((char *)"conditiontest",13);

	Exit(0);
}

/**
 * The testcases to prove the correctness of the "DestroyCondition" implementation
 */
void testcase4()
{

	int conditionId=-1;
	int rv;
	int lockId,i;

	Print("DESTROYCONDITION SYSTEM CALL TEST\n\n");
	Print("*********************************************************\n");
	Print("NEGATIVE TEST CASES\n");
	Print("*********************************************************\n");

	Print("[Test1] Illegal CVId\nCondition Variable Id is out of range\n");
	DestroyCondition(3000);
	Print("--------------------------------------------------------\n");
	Print("[Test2] Invalid CV Delete : \nTrying to delete a CV which is already deleted to simulate error\n");
	conditionId = CreateCondition((char *)"dummyCondition",14);
	DestroyCondition(conditionId);
	DestroyCondition(conditionId);

	Print("--------------------------------------------------------\n");
	Print("[Test3] Invalid CV Delete : \nTrying to delete a CV which was never created\n");
	DestroyCondition(1050);

	Print("--------------------------------------------------------\n");
	Print("[Test4] Invalid CV Delete : \nTrying to delete a CV which is currently in use\n");
	Fork(createConditionInUse);
	Fork(deleteInUseCondition);
	Yield();
	Yield();
	Yield();

	Print("--------------------------------------------------------\n");
	Print("[Test5] Invalid CV Delete : \nTrying to delete a CV which does not belong to current process\n");

	rv = Exec("../test/dcv",11);
	rv = Exec("../test/dcv2",12);
	for(i=0;i<3;i++)
		{
			Yield();
		}

	Print("\n\n*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test1] Deleting a CV\nCreated a dummyCV and deleted it to simulate normal behavior\n");
	conditionId = CreateCondition((char *)"dummyCon",8);
	DestroyCondition(conditionId);

	Exit(0);
}

/**
 * The testcases to prove the correctness of the "Acquire" implementation
 */
void testcase5()
{
	int lockId=-1;
	int i=0;
	int rv;

	Print("ACQUIRE SYSTEM CALL TEST\n\n");
	Print("*********************************************************\n");
	Print("NEGATIVE TEST CASES\n");
	Print("*********************************************************\n");

	Print("[Test1] Invalid lockId Acquire : \nAcquiring the lockID exceeding the maximum number of locks\n");
	Acquire(510);

	Print("--------------------------------------------------------\n");
	Print("[Test2] Invalid lockId Acquire : \nnegative lockId passed to simulate error\n");
	Acquire(-2);

	Print("--------------------------------------------------------\n");
	Print("[Test3] Acquire non-existent lock : \nTry to acquire a lock which is not existing / not created\n");
	Acquire(450);

	Print("--------------------------------------------------------\n");
	Print("[Test4] Address-space mismatch : \nTry to acquire a lock which is not part of the current address-space\n");
	rv = Exec("../test/exec",12);
	rv = Exec("../test/exec2",13);
	for(i=0;i<3;i++)
	{
		Yield();
	}

	Print("\n\n*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test1] Acquire a lock \nCreated a valid lock and acquired it\n");

	lockId = CreateLock((char *)"lock",4);
	Acquire(lockId);
	/**
	 * Releasing the lockId for freeing up memory
	 */
	Release(lockId);
	DestroyLock(lockId);

	Exit(0);
}

/**
 * The testcases to prove the correctness of the "Release" implementation
 */
void testcase6()
{
	int rv,lockId=-1;

	Print("RELEASE SYSTEM CALL TEST\n\n");
	Print("*********************************************************\n");
	Print("NEGATIVE TEST CASES\n");
	Print("*********************************************************\n");

	Print("[Test1] Invalid lockId Release : \nReleasing the lockID exceeding the maximum number of locks\n");
	Release(510);

	Print("--------------------------------------------------------\n");
	Print("[Test2] Invalid lockId Release : \nnegative lockId passed to simulate error\n");
	Release(-2);

	Print("--------------------------------------------------------\n");
	Print("[Test3] Release non-existent lock : \nTry to release a lock which is not existing / not created\n");
	Release(450);

	Print("--------------------------------------------------------\n");
	Print("[Test4] Address-space mismatch : \nTry to release a lock which is not part of the current address-space\n");
	rv = Exec("../test/exec",12);
	Release(0);

	Print("\n\n*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test1] Release a lock \nAcquired a valid lock & the released it to simulate normal behavior\n");

	lockId = CreateLock((char *)"lock",4);
	Acquire(lockId);
	/**
	 * Releasing the lockId for freeing up memory
	 */
	Release(lockId);
	DestroyLock(lockId);

	Exit(0);

}

/**
 * The testcases to prove the correctness of the "Wait/Signal/Broadcast" implementation
 */
void testcase7()
{
	int negativeCVId=-1;
	int negativeLockId=-1;
	int hugeLockId=9999;
	int hugeCVId=9999;

	Print("WAIT/SIGNAL/BROADCAST SYSTEM CALL TEST\n\n");
	Print("*********************************************************\n");
	Print("NEGATIVE TEST CASES\n");
	Print("*********************************************************\n");

	Print("[Test1] Waiting on invalid lock/condition id\nPassing -ve lock/condition id to simulate error\n");
	Wait(negativeCVId,negativeLockId);
	Print("--------------------------------------------------------\n");

	Print("[Test2] Waiting on invalid lock/condition id\nPassing out of range lock/condition id to simulate error\n");
	Wait(hugeCVId,hugeLockId);
	Print("--------------------------------------------------------\n");

	Print("[Test3] Signaling on invalid lock/condition id\nPassing -ve lock/condition id to simulate error\n");
	Signal(negativeCVId,negativeLockId);
	Print("--------------------------------------------------------\n");
	Print("[Test4] Signaling on invalid lock/condition id\nPassing out of range lock/condition id to simulate error\n");
	Signal(hugeCVId,hugeLockId);
	Print("--------------------------------------------------------\n");

	Print("[Test5] Broadcasting on invalid lock/condition id\nPassing -ve lock/condition id to simulate error\n");
	Broadcast(negativeCVId,negativeLockId);
	Print("--------------------------------------------------------\n");

	Print("[Test6] Broadcasting on invalid lock/condition id\nPassing out of range lock/condition id to simulate error\n");
	Broadcast(hugeCVId,hugeLockId);

	Print("\n\n*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test1] Forking 3 threads to simulate wait/signal/broadcast system call behavior\n");
	Exec("../test/combined",16);
	Exit(0);

}

/**
 * The testcases to prove the correctness of the "Fork" implementation
 */
void testcase8()
{

	int i,rv;

	Print("FORK SYSTEM CALL TEST\n\n");
	Print("*********************************************************\n");
	Print("NEGATIVE TEST CASES\n");
	Print("*********************************************************\n");

	Print("[Test1] Forking a thread out of address-space\nSimulate Error by passing out of range Virtual Address\n");
	Fork(0xffffff00);

	Print("\n\n*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test1] Forking 3 threads:\n");
	for(i=0;i<3;i++)
	{
		Print1("Thread %d forked\n",i);
		Fork(forktest);
	}
	Print("--------------------------------------------------------\n");
	Print("[Test2] Wrinkle Issue Simulation\n");
	rv = Exec("../test/wrinkle",16);
	Exit(0);
}

/**
 * The testcases to prove the correctness of the "Exec" implementation
 */
void testcase9()
{

	int rv;
	Print("EXEC SYSTEM CALL TEST\n\n");
	Print("*********************************************************\n");
	Print("NEGATIVE TEST CASES\n");
	Print("*********************************************************\n");

	Print("[Test1] Invalid Call:\nFile name provided to the syscall was invalid\n");
	rv = Exec("../test/blabla",14);
	Print("--------------------------------------------------------\n");

	Print("[Test2] Invalid Address-space used:\nAddress-space used is out of the range\n");
	rv = Exec((char *)0xffffff00,10);

	Print("\n\n*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test1] Executing Executables\nThe same executable is twice executed\n\n");
	rv = Exec("../test/exec",12);
	rv = Exec("../test/exec",12);
	Exit(0);

}

/**
 * The testcases to prove the correctness of the "Exit" implementation
 */
void testcase10()
{
	int i,rv;

	Print("EXIT SYSTEM CALL TEST\n\n");
	Print("\n\n*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test1] Exiting a Last Thread in Process\nSimulating Last thread in Exiting process\n\n");
	rv = Exec("../test/exec",12);
	for(i=0;i<10;i++)
	{
		Yield();
	}
	Print("--------------------------------------------------------\n");
	Print("[Test2] Exiting a Last Thread in Last Process\nSimulating Last thread in Last process\n\n");
	Exit(0);
}

/**
 * The testcases to prove the correctness of the "Two Concurrent Home Depot Simulation" implementation
 */
void testcase11()
{
	int rv;
	Print("TWO CONCURRENT HOME DEPOT SIMULATION\n\n");
	Print("*********************************************************\n");
	Print("Customer = 20 , Clerk / Cash-register = 3 , StockBoy = 3\n");
	Print("*********************************************************\n");
	Exec("../test/Problem2",16);
	Exec("../test/Problem2",16);
	
	Exit(0);
}

/**
 * The testcases to prove the correctness of the "Two Concurrent Home Depot Simulation" implementation
 */
void testcase12()
{
	int input;
	int i;
	Print("USER DEFINED CONCURRENT HOME DEPOT SIMULATION\n\n");
	Print("*********************************************************\n");
	Print("Customer = 20 , Clerk / Cash-register = 3 , StockBoy = 3\n");
	Print("*********************************************************\n");
	Print("Enter a value between 1 to 5: ");
	input=Scan();
	Print("\n");
	if(input>0 && input<6 )
	{
		for(i=0;i<input;i++)
		{
			Exec("../test/Problem2",16);
		}
	}
	else
	{
		Print("THE CURRENT SIZE OF PHYISICAL MEMORY CANNOT SUPPORT MORE THAN 5 INSTANCES OF HOME DEPOT SIMULATION..SORRY!!!!\n\n");
	}
	Exit(0);
}

int main() {

	int testcase;

	Print(" 1.CreateLock System call Tests\n");
	Print(" 2.DestroyLock System call Tests\n");
	Print(" 3.CreateCondition System call Tests\n");
	Print(" 4.DestroyCondition System call Tests\n");
	Print(" 5.Acquire System call Tests\n");
	Print(" 6.Release System call Tests\n");
	Print(" 7.Wait/Signal/Broadcast System call Tests\n");
	Print(" 8.Fork System call Tests\n");
	Print(" 9.Exec System call Tests\n");
	Print("10.Exit System call Tests\n");
	Print("11.Two concurrent Home Depot Simulation\n");
	Print("12.Run User defined instances of Home Depot Simulation\n");
	Print("\n");


	Print("Enter Choice:\n");

	testcase=Scan();
	/*testcase=11;*/

	Print("\n\n");

	switch(testcase)
	{
	case 1:
		testcase1();
		break;
	case 2:
		testcase2();
		break;
	case 3:
		testcase3();
		break;
	case 4:
		testcase4();
		break;
	case 5:
		testcase5();
		break;
	case 6:
		testcase6();
		break;
	case 7:
		testcase7();
		break;
	case 8:
		testcase8();
		break;
	case 9:
		testcase9();
		break;
	case 10:
		testcase10();
		break;
	case 11:
		testcase11();
		break;
	case 12:
		testcase12();
	default:
		Print("Please enter a valid test-case option\n");
		break;

	}


}
